#include "bsp_usart.h"
#include "usart.h"
#include <stdio.h>
#include <stdarg.h>
#include "string.h"
#include "gd32f3x0.h"

uint8_t rxbuffer[RX_BUFFER_MAX];
uint8_t txbuffer[TX_BUFFER_MAX];

int usart_dma_tx_init(uint8_t *buff, uint16_t buff_len)
{
	dma_parameter_struct dma_init_struct;
	/* deinitialize DMA channel 1*/
	dma_deinit(DMA_CH1);
	dma_struct_para_init(&dma_init_struct);
	dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
	dma_init_struct.memory_addr = (uint32_t)buff;
	dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
	dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
	dma_init_struct.number = buff_len;
	dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USART0);
	dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
	dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
	dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
	dma_init(DMA_CH1, &dma_init_struct);

	dma_circulation_disable(DMA_CH1);
	dma_memory_to_memory_disable(DMA_CH1);

	dma_channel_enable(DMA_CH1);
	return 0;
}

int usart_dma_rx_init(uint8_t *buff, uint16_t buff_len)
{
	dma_parameter_struct dma_init_struct;
	/* deinitialize DMA channel 2*/
	memset(buff,0x00,buff_len);
	dma_deinit(DMA_CH2);
	dma_struct_para_init(&dma_init_struct);
	dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
	dma_init_struct.memory_addr = (uint32_t)buff;
	dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
	dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
	dma_init_struct.number = buff_len;
	dma_init_struct.periph_addr = (uint32_t) &USART_RDATA(USART0);
	dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
	dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
	dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
	dma_init(DMA_CH2, &dma_init_struct);

	dma_circulation_disable(DMA_CH2);
	dma_memory_to_memory_disable(DMA_CH2);

	dma_channel_enable(DMA_CH2);
	return 0;
}

int usart_dma_send(uint32_t usart, uint8_t *buffer, uint16_t buf_len)
{
	int ret = -1;
	if(buffer == NULL)
	{
		return ret;
	}
	memcpy(txbuffer,buffer,buf_len);
	usart_dma_tx_init(txbuffer, buf_len);
	/* USART DMA enable for transmission and reception */
	usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
	/* wait DMA Channel transfer complete */
	while(RESET == dma_flag_get(DMA_CH1, DMA_FLAG_FTF));
	ret = 0;
	
	return ret;
}

uint8_t usart_dma_recv(uint32_t usart, uint8_t *buffer, uint16_t buf_len)
{
	uint8_t ret = 0;
	usart_dma_rx_init(rxbuffer,RX_BUFFER_MAX);
	usart_dma_receive_config(usart, USART_DENR_ENABLE);
	
	/* wait DMA channel transfer complete */
	while(1)
	{
		if(RESET != dma_flag_get(DMA_CH2, DMA_FLAG_FTF))
		{
			//printf("Buffer is full\n");
			break;
		}
		if(strstr((const char *)rxbuffer, "OK\r\n"))
		{
			//printf("Got end\n");
			break;
		}
	}
	
	ret = strlen((char *)rxbuffer);
	memset(buffer,0x00,buf_len);
	memcpy(buffer, rxbuffer, ret);
	
	printf("%s\n", buffer);
	return ret;
}

/*!
    \brief      configure the USART0 GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usart0_gpio_config(void)
{
    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
}

void usart1_gpio_config(void)
{
    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_2);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_3);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);
}
/*!
    \brief      configure the USART0
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usart0_config(void)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    usart_enable(USART0);
}

void usart1_config(void)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);

    /* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, 115200U);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);

    usart_enable(USART1);
}
